﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using SwiftMVVM.ViewModel;

namespace MineSweeper.Data
{
    /// <summary>
    /// Represents a minesweeper tile
    /// </summary>
    public abstract class Tile : BindingObject
    {
        /// <summary>
        /// Since the Tile object is wrapped with a NotifyProxy
        /// we can increase the speed of creating new instances by generating/reusing an allocator.
        /// </summary>
        private static readonly Func<object[], object> allocator =
            NotifyProxyTypeManager.GetAllocatorExact<Tile>(
            typeof(TileMap), typeof(int), typeof(TileType));

        /// <summary>
        /// The adjacent tiles to this tile
        /// </summary>
        public IEnumerable<Tile> AdjacentTiles { get; private set; }

        /// <summary>
        /// Reference to the parent tile map
        /// </summary>
        public TileMap Parent { get; private set; }

        /// <summary>
        /// Represents the type of the tile
        /// </summary>
        [NotificationProperty]
        public virtual TileType Type { get; set; }

        /// <summary>
        /// Returns the count of nearby mines. 
        /// </summary>
        [NotificationProperty]
        public virtual int NearbyMineCount { get; set; }

        /// <summary>
        /// Represents the current state of the tile
        /// </summary>
        [NotificationProperty]
        public virtual TileState State { get; set; }

        [NotificationProperty]
        public virtual bool IsFocused { get; protected set; }

        public void Focus()
        {
            if (this.Parent.FocusedTile != null)
            {
                this.Parent.FocusedTile.IsFocused = false;
            }
            this.Parent.FocusedTile = this;
            this.IsFocused = true;
        }

        public void ClearFocus()
        {
            this.Parent.FocusedTile = null;
            this.IsFocused = false;
        }

        /// <summary>
        /// Constructs a new Tile
        /// </summary>
        /// <param name="parent">The parent tile map</param>
        /// <param name="type">The tile type</param>
        public Tile(TileMap parent, int index, TileType type)
        {
            this.Parent = parent;
            this.Type = type;
            var allTileWidth = Parent.Width + 2;
            this.AdjacentTiles = new int[] 
                { 
                    index - allTileWidth - 1, 
                    index - allTileWidth,
                    index - allTileWidth + 1,
                    index + allTileWidth - 1,
                    index + allTileWidth,
                    index + allTileWidth + 1,
                    index - 1,
                    index + 1
                }.Select(t => this.Parent.AllTiles[t]);
        }

        /// <summary>
        /// Constructs a new Tile
        /// </summary>
        /// <param name="parent">The parent tile map</param>
        /// <param name="type">The tile type</param>
        public static Tile Create(TileMap parent, int index, TileType type)
        {
            return allocator(new object[]{parent, index, type}) as Tile;
        }
    }
}
